﻿' Copyright © Microsoft Corporation.  All Rights Reserved.
' This code released under the terms of the 
' Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
' <copyright file="StretchBox.vb" company="Microsoft">
'     Copyright © Microsoft Corporation. All rights reserved.
' </copyright>
' <summary>Implements the StretchBox class</summary>
' <author>Microsoft Expression Encoder Team</author>

Imports Microsoft.VisualBasic
Imports System
Imports System.Diagnostics
Imports System.Globalization
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Markup
Imports System.Windows.Media

Namespace ExpressionMediaPlayer

	''' <summary>
	''' Stretch box control.
	''' </summary>
    <ContentProperty("Child"), TemplatePart(Name:="ChildBorder", Type:=GetType(Border))> _
 Public Class StretchBox
        Inherits Control
        ''' <summary>
        ''' ChildBorder property string.
        ''' </summary>
        Private Const ChildBorder As String = "ChildBorder"
        ''' <summary>
        ''' Child border.
        ''' </summary>
        Private _childBorder As Border
        ''' <summary>
        ''' Original size.
        ''' </summary>
        Private sizeOriginal As Size
        ''' <summary>
        ''' Scaling factor.
        ''' </summary>
        Private scalingFactor As Double = 1.0
        ''' <summary>
        ''' The size we actually need.
        ''' </summary>
        Private sizeActuallyNeeded As Size
        ''' <summary>
        ''' Child dependency property.
        ''' </summary>
        Public Shared ReadOnly ChildProperty As DependencyProperty = DependencyProperty.Register("Child", GetType(UIElement), GetType(StretchBox), New PropertyMetadata(New PropertyChangedCallback(AddressOf StretchBox.OnChildPropertyChanged)))
        ''' <summary>
        ''' Initializes a new instance of the StretchBox class.
        ''' </summary>
        Public Sub New()
            DefaultStyleKey = GetType(StretchBox)
        End Sub
        ''' <summary>
        ''' Gets or sets the child UI element.
        ''' </summary>
        Public Property Child() As UIElement
            Get
                Return TryCast(GetValue(ChildProperty), UIElement)
            End Get
            Set(ByVal value As UIElement)
                SetValue(ChildProperty, value)
            End Set
        End Property
        ''' <summary>
        ''' Overrides OnApplyTemplate().
        ''' </summary>
        Public Overrides Sub OnApplyTemplate()
            MyBase.OnApplyTemplate()
            _childBorder = TryCast(GetTemplateChild(ChildBorder), Border)
            sizeOriginal = New Size(0, 0)
            OnChildChanged()
        End Sub
        ''' <summary>
        ''' Dependency property handler for the child property.
        ''' </summary>
        ''' <param name="dobj">Source dependency object.</param>
        ''' <param name="args">Event args.</param>
        Private Shared Sub OnChildPropertyChanged(ByVal dobj As DependencyObject, ByVal args As DependencyPropertyChangedEventArgs)
            TryCast(dobj, StretchBox).OnChildChanged()
        End Sub
        ''' <summary>
        ''' Event handler for the child property changed event.
        ''' </summary>
        Private Sub OnChildChanged()
            If _childBorder IsNot Nothing Then
                _childBorder.Child = Child
            End If
        End Sub
        ''' <summary>
        ''' Overrides MeasureOverride().
        ''' </summary>
        ''' <param name="availableSize">The available size.</param>
        ''' <returns>Returns the measured size.</returns>
        Protected Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
            If _childBorder IsNot Nothing Then
                If sizeOriginal.Width = 0 Then ' Make this measurement only once per instance
                    _childBorder.Measure(New Size(Double.PositiveInfinity, Double.PositiveInfinity))
                    sizeOriginal = _childBorder.DesiredSize
                End If

                Dim desiredSizeMax As Size = sizeOriginal

                _childBorder.Measure(availableSize)
                Dim desiredSizeFit As Size = _childBorder.DesiredSize

                Dim scalingFactorX As Double = 1.0
                If availableSize.Width < desiredSizeFit.Width Then
                    scalingFactorX = CLng(availableSize.Width) \ CLng(desiredSizeFit.Width)
                ElseIf availableSize.Width < desiredSizeMax.Width Then
                    scalingFactorX = CLng(availableSize.Width) \ CLng(desiredSizeMax.Width)
                End If

                Dim scalingFactorY As Double = 1.0
                If availableSize.Height < desiredSizeFit.Height Then
                    scalingFactorY = CLng(availableSize.Height) \ CLng(desiredSizeFit.Height)
                ElseIf availableSize.Height < desiredSizeMax.Height Then
                    scalingFactorY = CLng(availableSize.Height) \ CLng(desiredSizeMax.Height)
                End If

                scalingFactor = Math.Min(scalingFactorX, scalingFactorY)
                If Double.IsPositiveInfinity(availableSize.Width) OrElse Double.IsPositiveInfinity(availableSize.Height) Then
                    sizeActuallyNeeded = New Size(desiredSizeFit.Width * scalingFactor, desiredSizeFit.Height * scalingFactor)
                Else
                    sizeActuallyNeeded = New Size(availableSize.Width / scalingFactor, availableSize.Height / scalingFactor)
                End If
            End If
            Return sizeActuallyNeeded
        End Function
        ''' <summary>
        ''' Overrides ArrangeOverride().
        ''' </summary>
        ''' <param name="finalSize">The final size.</param>
        ''' <returns>The returned final size.</returns>
        Protected Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
            If _childBorder IsNot Nothing Then
                Dim st As New ScaleTransform()
                st.ScaleX = scalingFactor
                st.ScaleY = scalingFactor
                st.CenterX = 0
                st.CenterY = 0

                _childBorder.RenderTransform = st

                _childBorder.Arrange(New Rect(0, 0, sizeActuallyNeeded.Width, sizeActuallyNeeded.Height))
            End If

            Return finalSize
        End Function
    End Class
End Namespace
